<?php

/**
 * @author GreyMag
 * @copyright 2009
 */
 
class SecureRequest
{
	/**
	 * Сообщение об ошибке
	 */  
	public $error,
	/**
	 * Номер ошибки
	 */ 
		   $errno,
	/**
	 * Посланные поля
	 */ 	   
		   $requestFields;
		   
	private $_secureCode, // защищенный ключ
			$_apiId, // идентификатор приложения
			$_method, // название метода API из общего списка функций
			$_parameters = array(), // массив передаваемых параметров
			$_v = '2.0', // версия API - необязательный параметр
			$_format = 'XML', // формат возвращаемых данных – XML или JSON. По умолчанию XML - необязательный параметр
			$_requestUrl = 'http://api.vkontakte.ru/api.php', // url для запроса
			$_testMode = false; // тестовый режим
	
	// список защищёных методов		
	const 
		  /**
		   * Метод отправляет уведомление пользователю
		   */ 
		  SEND_NOTIFICATION = 'secure.sendNotification',	
	      /**
		   * Метод сохраняет строку статуса приложения 
		   * для последующего вывода в общем списке приложений на странице пользоваетеля
		   */ 
		  SAVE_APP_STATUS = 'secure.saveAppStatus',
	      /**
		   * Метод возвращает платежный баланс приложения
		   */ 
		  GET_APP_BALANCE = 'secure.getAppBalance',
	      /**
		   * Метод возвращает баланс пользователя на счету приложения
		   */ 
		  GET_BALANCE = 'secure.getBalance',
	      /**
		   * Метод переводит голоса со счета приложения на счет пользователя
		   */ 
		  ADD_VOTES = 'secure.addVotes',
	      /**
		   * Метод списывает голоса со счета пользователя на счет приложения
		   */ 
		  WITHDRAW_VOTES = 'secure.withdrawVotes',
	      /**
		   * Метод переводит голоса со счета одного пользователя на счет другого в рамках приложения
		   */ 
		  TRANSFER_VOTES = 'secure.transferVotes',
	      /**
		   * Метод возвращает историю транзакций внутри приложения
		   */ 
		  GET_TRANSACTIONS_HISTORY = 'secure.getTransactionsHistory',
          
          WAIL_GETPHOTOUPLOADSERVER = "wall.getPhotoUploadServer",
          
          WAIL_SAVEPOST = "wall.savePost",
          /**
           * Таймаут между запросами ( не болше трех в секунду )
           */
          KONTAKT_REQUEST_DELAY = .3;  

	
	public function __construct( $apiId, $testMode = false )
	{
		$this->_apiId = $apiId;
		$this->_secureCode = SECURE_CODE;
		
		$this->setparameters();
		
		if( $testMode )
		{
			$this->_testMode = true;
			$this->_parameters['test_mode'] = '1';
		}
	}
	
    function format($format){
        $this->_format = $format;
        $this->setparameters();
    }
    
    private function setparameters(){
        $this->_parameters['api_id'] = $this->_apiId;
		$this->_parameters['v'] = $this->_v;
		$this->_parameters['format'] = $this->_format;
    }
    
	/**
	 * SecureRequest::request()
	 * Отправка запроса на ВКонтакте
	 * @param mixed $method Название метода
	 * @param array $parameters Массив передаваемых параметров со значениями
	 * @return Объект ответа с ВКонтакте
	 */
	public function request( $method, $parameters = array(), $_url = "" )
	{
		$this->_parameters['method'] = $method;
        if($_url != ""){
            $this->_requestUrl = $_url;
        }
		
		if( is_array( $parameters ) )
			$this->_parameters = array_merge( $this->_parameters, $parameters );
		
		$this->_parameters['timestamp'] = $this->getTimestamp();
		$this->_parameters['random'] = $this->getRandom();
		
		$queryString = $this->createQueryString();        
		
	    $curl = curl_init();
	
	    curl_setopt( $curl, CURLOPT_URL, $this->_requestUrl );
	    curl_setopt( $curl, CURLOPT_POST, 1);
	    curl_setopt( $curl, CURLOPT_POSTFIELDS, $queryString );
	    curl_setopt( $curl, CURLOPT_RETURNTRANSFER , 1);
	
	    $result = curl_exec( $curl );
	    $error = curl_getinfo( $curl );
	    
		curl_close( $curl );
		
	    if ( $error['http_code'] != "200" ) 
		{
			$this->errno = '0';
			$this->error = 'Ошибка соединения';
			return false;
		}elseif( $this->_format == 'JSON' && isset($_result->error) ){
            $_result = json_decode($result);              
            $_result->error = (Array)$_result->error;
            $this->errno = $_result->error['error_code'];
			$this->error = $_result->error['error_msg'];        		
            return false;                      
		}	
	    else
		{
			if($this->_parameters['format'] && $this->_parameters['format'] == 'JSON'){
			     $answer =  json_decode( $result );
                 #return $answer->response;
                 if( !isset( $answer->response )){
                    if( !empty( $answer->error_msg) ) 
				        {
					       $this->errno = @$answer->error_code;
					       $this->error = @$answer->error_msg;
					       $this->requestFields = @$answer->request_params;
				        }
				    else $this->error = 'Неопознанная ошибка. ';
                    return false;
                 }
                 return $answer;
                 #if($answer)  
			}else{
			     $answer = simplexml_load_string( $result );
                 if( $answer->getName() !== 'response' ) 
			     {
                    if( !empty( $answer->error_msg ) ) 
				        {
					       $this->errno = $answer->error_code;
					       $this->error = $answer->error_msg;
					       $this->requestFields = $answer->request_params->asXML();
				        }
				    else $this->error = 'Неопознанная ошибка. ' . $answer->asXML();
				
				    return false;	
			     }else return $answer; 
			}
            #$answer =  $result ;	    	
		} 
	    /*{
	        header( 'Content-type: text/xml' );	
			echo '<?xml version="1.0" encoding="utf-8"?>
				  <xml>';
			echo '<![CDATA[Запрос: ' . $queryString . ']]>'; 		
	        echo substr( $result, 39 ) ;
			echo '</xml>'; 
	    }*/
		
		//header( 'Location: ' . $this->_requestUrl . '?' . $queryString );
	}
	
	// формируем строку запроса
	private function createQueryString()
	{
		$string = '';
		
		foreach( $this->_parameters as $name=>$value ) $string .= $name . '=' . $value . '&';
		
		$string .= 'sig=' . $this->createSIG();
		
		return $string; 
	}
	
	// создаем подпись, в целях безопасности
	private function createSIG()
	{
		$string = '';
		
		ksort( $this->_parameters, SORT_STRING );
		
		foreach( $this->_parameters as $name=>$value ) $string .= $name . '=' . $value;
		
		$string .= $this->_secureCode;
		
		return md5( $string );
	}
	
	// любое случайное число для обеспечения уникальности запроса 
	private function getRandom(  $length = 'rand', $max = 6, $min = 12 )
	{
		if( $length == 'rand' ) $length = rand( $max,$min );    
	
		$symb = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
		$str = '';
		for( $i = 0; $i < $length; $i++ ) $str .= substr( $symb, rand( 0, strlen( $symb ) ), 1 );
		
		return $str;
	}
	
	// текущее значение unixtime на сервере
	private function getTimestamp()
	{
		return date( 'U' );
	}
}
?>